package com.toobigtofail
{
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
	import net.flashpunk.Sfx;
	import net.flashpunk.graphics.Text;
	import net.flashpunk.utils.Input;
	import net.flashpunk.utils.Key;
	
	import punk.bloom.BloomLighting;
	import punk.bloom.BloomWrapper;
	
	public class Player extends Entity
	{
		[Embed(source="/assets/sfx/death1.mp3")] private const DEATHSFX1:Class;
		[Embed(source="/assets/sfx/death2.mp3")] private const DEATHSFX2:Class;
		[Embed(source="/assets/sfx/death3.mp3")] private const DEATHSFX3:Class;
		
		private static const PRECISION_SPEED:int = 9;
		private static const NUM_SECTIONS:int = 6;
		
		public static const SLOW_SECTION:int   = 1;
		public static const TINY_SECTION:int   = 2;
		public static const PRECISION_SECTION:int = 3;
		
		private static const ACCELERATION:Number = 0.3;
		public static const DECELERATION:Number = 0.02;
		public static const MAX_VELOCITY:Number = 6;
		
		public static const MAX_ASSIGNABLE_SECTIONS:int = 4;
		
		private static const BROADCAST_DEATH_TIME:Number = 3;
		private var _broadcastDeathTimer:Number = BROADCAST_DEATH_TIME;
		
		private var _deathSfxArray:Array = new Array(
							new Sfx(DEATHSFX1),
							new Sfx(DEATHSFX2),
							new Sfx(DEATHSFX3)
		);
							
		
		/* amount of bloom and quality of bloom desired */
		private static const BLOOM:Number = 10.0;
		private static const BLOOM_QUALITY:int = 1;
		
		/* bloom effect */
		public var bloom:BloomLighting = new BloomLighting(BLOOM, BLOOM_QUALITY);
		
		public var dx:Number = 0, dy:Number = 0;
		private var _head:PlayerSection = null;
		private var _iAmHead:Boolean = false;
		
		private var _state:String = "playing";
		
		public var mySection:int   = -1;
		public var myPeerID:String = null;
		
		private static const TINY_TIME:Number = 5;
		private var _tinyTimer:Number = TINY_TIME;
		private var _isTiny:Boolean = false;
		
		private static const PRECISION_TIME:Number = 5;
		private var _precisionTimer:Number = PRECISION_TIME;
		public var _isPrecision:Boolean = false;
		
		public function Player(x:Number=0, y:Number=0) {
			this.x = x;
			this.y = y;
			
			setHitbox(0,0);
		}
		
		override public function added():void {
			_head = new PlayerSection(x,y);
			world.add(_head);
			var pSection:PlayerSection = _head;
			for (var i:int = 1; i < NUM_SECTIONS; i++) {
				pSection = (world.add(new PlayerSection(0,0,pSection)) as PlayerSection);
			}
			
			//set the layer and color of the bloom, and add it to the world
			bloom.layer = -1;
			bloom.color = 0xFFFFFF;
			(world as Game).add(bloom);
		}
		
		override public function update():void {
			super.update();
			
			switch(_state) {
				case "playing":
					if (_iAmHead) {
						var oldY:Number = y;
						if (_isPrecision) {
							dy = 0;
							if (Input.check(Key.UP)) {
								y -= PRECISION_SPEED;
							} else if (Input.check(Key.DOWN)) {
								y += PRECISION_SPEED;
							}
							_head.y = y;
						} else {
							if (Input.check(Key.UP)) {
								dy = Math.max(dy - ACCELERATION, -MAX_VELOCITY);
							} else if (Input.check(Key.DOWN)) {
								dy = Math.min(dy + ACCELERATION, MAX_VELOCITY);
							} else {
								dy = dy < 0 ? Math.min(0, dy + DECELERATION) : Math.max(0, dy - DECELERATION);
							}
							
							x = _head.x;
							y = _head.y;
						}
						
						var e:Entity = _head.collide("enemy", _head.x, _head.y);
						if (e) {
							die();
							(world as Game).actionHandler.sendAction(GameAction.DIE);
						} else {
							(world as Game).actionHandler.sendAction(GameAction.UPDATE_POSITION, {x: x, y: y, dx: dx, dy: dy});
						}
						
						if (y > FP.screen.height - height - 240) {
							y = oldY;
							dy = -2;
							_head.y = y;
						}
					} else {
						_head.x = x;
						_head.y = y;
					}
		
					if (_head) {
						_head.dy = dy;
						_head.dx = dx;
					}
					
					// check non-head actions
					if (mySection == SLOW_SECTION && Input.check(Key.SPACE)) {
						(world as Game).updateEnemyData(true);
						(world as Game).ouroboros.isSlow = true;
						(world as Game).actionHandler.sendAction(GameAction.SLOW_TIME);
					}
					else if (mySection == TINY_SECTION) {
						if (Input.check(Key.SPACE) && !_isTiny) {
							_tinyTimer = TINY_TIME;
							makeTiny();
							_isTiny = true;
							(world as Game).actionHandler.sendAction(GameAction.MAKE_TINY);
						} else if (_isTiny) {
							_tinyTimer -= FP.elapsed;
							if (_tinyTimer <= 0) {
								makeNormal();
								_isTiny=false;
								(world as Game).actionHandler.sendAction(GameAction.MAKE_NORMAL);
							}
						}
					}
					else if (mySection == PRECISION_SECTION) {
						if (Input.check(Key.SPACE) && !_isPrecision) {
							_isPrecision = true;
							_precisionTimer = PRECISION_TIME;
							(world as Game).actionHandler.sendAction(GameAction.MAKE_PRECISION);
						} else if (_isPrecision) {
							_precisionTimer -= FP.elapsed;
							if (_precisionTimer <= 0) {
								_isPrecision = false;
								(world as Game).actionHandler.sendAction(GameAction.MAKE_PRECISION_NORMAL);
							}
						}
					}
					
					break;
				
				case "dead":
					if (_iAmHead) {
						this._broadcastDeathTimer -= FP.elapsed;
						if (this._broadcastDeathTimer <= 0) {
							(world as Game).actionHandler.sendAction(GameAction.DIE);
							_broadcastDeathTimer = BROADCAST_DEATH_TIME;
						}
						
						if (Input.check(Key.R)) {
							(world as Game).background.speed = (world as Game)._isSlow ? BaseEnemy.SLOW_SPEED : BaseEnemy.FAST_SPEED;
							(world as Game).background.deceleration = 0;
							restart();
							(world as Game).actionHandler.sendAction(GameAction.RESTART);
						}
					}
					break;
					
			}
		}
		
		public function die():void {
			if (_state != "dead") {
				_state = "dead";
				if((FP.world as Game)._playMusic.playing)
				{
					(FP.world as Game)._playMusic.stop();
				}
				if((FP.world as Game)._startSong.playing)
				{
					(FP.world as Game)._startSong.stop();
				}
				_deathSfxArray[FP.rand(_deathSfxArray.length)].play();
				(FP.world as Game)._deathSong.loop();
				
				(world as Game).updateEnemyData(false,false,true);
				var t:Text = new Text(_iAmHead ? "Press 'R' to Restart" : "Waiting for the Leader to Restart", 300, 20);
				t.size = 16;
				(world as Game).display.width = t.width;
				(world as Game).display.graphic = t;
				var pSection:PlayerSection = _head;
				while (null != pSection) {
					pSection.die();
					pSection = pSection.previousSection;
				}
			}
		}
		
		public function restart():void {
			if (_state == "dead") {
				_state = "playing";
				
				(FP.world as Game)._deathSong.stop();
				(FP.world as Game)._startSong.play();


				
				var enemies:Array = new Array;
				(world as Game).getType("enemy", enemies);
				for each (var e:BaseEnemy in enemies) {
					(world as Game).remove(e);
				}
				
				y = FP.screen.height/2;
				x = FP.screen.width/2;
				_head.y = y;
				_head.x = x;
				dx = 0;
				dy = 0;
				
				var pSection:PlayerSection = _head;
				while (null != pSection) {
					pSection.restart();
					pSection = pSection.previousSection;
				}
				
				(world as Game).display.graphic = null;
			}
		}
		
		public function assignSection(sectionNum:int, peerID:String):Boolean {
			var i:int = 0;
			var pSection:PlayerSection = _head;
			while (null != pSection && i < MAX_ASSIGNABLE_SECTIONS) {
				if (i == sectionNum) {
					if (peerID == this.myPeerID) {
						pSection.graphic = new BloomWrapper(pSection.graphic); 
						bloom.register(pSection.graphic as BloomWrapper);
						mySection = sectionNum;
					}
					
					pSection.peerID = peerID;
					if (null != myPeerID && peerID == myPeerID) {
						// for now, color the section i control red
						pSection.color = 0xFF0000;
						// if i took section 0, then I'm the head! I get fucking control!
						if (0 == i) _iAmHead = true;
					}
					pSection.alpha = 1;
					return true;
				}
				pSection = pSection.previousSection;
				i++;
			}
			return false;
		}
		
		public function getFirstUnusedSection():int {
			var pSection:PlayerSection = _head;
			var i:int = 0;
			while (null != pSection && i < MAX_ASSIGNABLE_SECTIONS) {
				if (null == pSection.peerID) {
					return i;
				}
				pSection = pSection.previousSection;
				i++;
			}
			return -1;
		}
		
		public function get numAssignedSections():int {
			var pSection:PlayerSection = _head;
			var i:int = 0;
			while (null != pSection) {
				pSection = pSection.previousSection;
				i++;
			}
			return i;
		}
		
		public function makeTiny():void {
			var pSection:PlayerSection = _head;
			while (null != pSection) {
				pSection.makeTiny();
				pSection = pSection.previousSection;
			}
		}
		
		public function makeNormal():void {
			var pSection:PlayerSection = _head;
			while (null != pSection) {
				pSection.makeNormal();
				pSection = pSection.previousSection;
			}
		}
		
		public function get iAmHead():Boolean { return _iAmHead; }
		public function get isDead():Boolean { return _state == "dead"; }
	}
}